package com.talkyun.openx.client.conn;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class HttpConnector extends BaseConnection {

    public static final Map<String, String> DEF_COOKIE_MAP = new ConcurrentHashMap<String, String>();
    public static final String CHARSET = "utf-8";

    public HttpConnector(String url) {
        this(url, 3000, true);
    }

    public HttpConnector(String url, int timeout, boolean keepAlive) {
        super(url, timeout, keepAlive);
    }

    public HttpResult send(String body) throws IOException {
        return this.sendWithHeader("POST", new HashMap<String, String>(), body);
    }

    public HttpResult sendWithHeader(String method, Map<String, String> header, String body) throws IOException {
        URL url2 = new URL(url);
        String host = url2.getHost() + ":" + url2.getPort();

        HttpURLConnection conn = super.getHttpURLConnection();
        try {
            conn.setRequestMethod(method);
            return doHandle(url2, host, conn, method, header, body);
        } finally {
            conn.disconnect();
        }
    }

    private HttpResult doHandle(URL url2, String host, HttpURLConnection conn, String method, Map<String, String> header, String body) throws IOException {
        this.setCookie(host, header);

        // write head
        for (Map.Entry<String, String> entry : header.entrySet()) {
            conn.setRequestProperty(entry.getKey(), entry.getValue());
        }

        // write body
        if (!isBlank(body) && ("POST".equalsIgnoreCase(method) || "PUT".equalsIgnoreCase(method))) {
            byte[] data = body.getBytes(CHARSET);
            conn.setRequestProperty("Content-Length", String.valueOf(data.length));
            OutputStream os = null;
            try {
                os = conn.getOutputStream();
            } catch (Throwable t) {
                throw new HttpNotConnectionException(url2.toString(), t);
            }
            os.write(data);
        }

        int status = conn.getResponseCode();
        HttpResult result = null;
        if (status == 200) {
            result = new HttpResult(status, this.doRead(conn.getInputStream()));
        } else {
            result = new HttpResult(status, this.doRead(conn.getErrorStream()));
        }

        // handle head
        return this.doHeader(host, conn, result);
    }

    private String doRead(InputStream is) throws IOException {
        byte[] buf = new byte[1024];
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
        for (int num; (num = is.read(buf)) != -1; ) {
            baos.write(buf, 0, num);
        }
        return baos.toString("utf-8");
    }

    private HttpResult doHeader(String host, HttpURLConnection conn, HttpResult result) {
        result.setHeader("Set-Cookie", conn.getHeaderField("Set-Cookie"));
        result.setHeader("Content-Encoding", conn.getHeaderField("Content-Encoding"));
        // handle cookie
        String cookie = conn.getHeaderField("Set-Cookie");
        if (cookie != null) {
            DEF_COOKIE_MAP.put(host, cookie);
        }
        return result;
    }

    private void setCookie(String key, Map<String, String> headers) {
        String cookie = DEF_COOKIE_MAP.get(key);
        if (cookie != null) {
            headers.put("Cookie", cookie);
        }
    }
}